package com.share.example.classload.config.model;

import com.share.common.utils.FileUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

@Slf4j
public class OutDirClassLoader extends URLClassLoader {
    private ClassLoader parent;

    private static URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
    private static final Method ADD_URL = initAddMethod();

    public OutDirClassLoader(URL[] urls) {
        super(urls);
    }

    public OutDirClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
        this.parent = parent;
    }

    private static Method initAddMethod() {
        try {
            Method addUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            addUrl.setAccessible(true);
            return addUrl;
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    public static void loadJar(String filepath) {
        if (filepath == null) {
            return;
        } else {
            File file = new File(filepath);
            if (file.exists()) {
                log.info("正在加载目录下的jar,path=" + filepath);
                loopFile(file);
                return;
            }
        }
        log.info("jar加载失败,path=" + filepath);
    }

    /**
     * 遍历目录加载jar
     *
     * @param file
     */
    private static void loopFile(File file) {
        if (file.isDirectory()) {
            File[] tmps = file.listFiles();
            for (File tmp : tmps) {
                loopFile(tmp);
            }
        } else {
            if (file.getAbsolutePath().endsWith(".jar")) {
                try {
                    ADD_URL.invoke(classLoader, file.toURI().toURL());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 系统会自动调用这个方法
     *
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> aClass = parent.loadClass(name);
        if (aClass != null) {
            return aClass;
        } else {
            log.info("这个类正在被加载fileName={}", name);
            byte[] bytes = FileUtil.readByte(name);
            int len = bytes.length;
            log.info("这个类正在被加载fileName={},len={}", name, len);
            return defineClass(null, bytes, 0, len);
        }
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        log.info("这个类正在被加载fileName={}", name);
        return super.loadClass(name);
    }
}
